
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Spring三级缓存解决循环依赖 - 学习卡片</title>
      <style>
        body { font-family: sans-serif; background-color: #f0f8ff; color: #333; display: flex; flex-direction: column; align-items: center; padding: 50px 20px; }
        .header h1 { font-size: 32px; }
        .grid-container { display: grid; grid-template-columns: repeat(3, 1fr); gap: 28px; width: 100%; max-width: 1200px; }
        .card-container { perspective: 1200px; cursor: pointer; height: 250px; }
        .card { width: 100%; height: 100%; position: relative; transform-style: preserve-3d; transition: transform 0.7s; border-radius: 16px; box-shadow: 0 4px 16px rgba(0,0,0,0.08); }
        .card-container.flipped .card { transform: rotateY(180deg); }
        .card-face { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; display: flex; flex-direction: column; box-sizing: border-box; border-radius: 16px; background-color: #fff; padding: 24px; }
        .card-back { background-color: #f0fff4; transform: rotateY(180deg); justify-content: space-between; }
        .card-category { font-size: 14px; color: #0052d9; margin-bottom: 8px; font-weight: 500; }
        .card-question { font-size: 20px; font-weight: 500; flex-grow: 1; display: flex; align-items: center; justify-content: center; text-align: center; }
        .card-answer-wrapper { flex-grow: 1; overflow-y: auto; }
        .card-answer { font-size: 15px; line-height: 1.7; }
        .card-footer { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 16px; margin-top: 16px; }
        .card-source { font-size: 13px; color: #8a919f; border-top: 1px solid #f0f0f0; padding-top: 12px; margin-top: 12px; }
      </style>
    </head>
    <body>
      <div class="header">
        <h1>Spring三级缓存解决循环依赖 - 学习卡片</h1>
      </div>
      <div class="grid-container">
        
    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">理论</div>
          <div class="card-question">Android中的BroadcastReceiver（广播接收器）扮演什么角色？它主要用于什么场景？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">理论</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">BroadcastReceiver是一个Android组件，它允许应用接收系统或其他应用发送的广播消息（Intents）。它主要用于响应系统范围的事件，例如网络状态变化、电池电量低或语言区域改变，从而实现应用间的通信和对系统事件的响应。</div>
          </div>
          <div class="card-source">来源: BroadcastReceiver 简介</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">类型</div>
          <div class="card-question">请解释普通广播（Normal Broadcasts）和有序广播（Ordered Broadcasts）之间的主要区别。</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">类型</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要区别在于传递方式和接收者行为。普通广播（使用`sendBroadcast()`）是完全异步的，所有接收者无序地同时接收广播。而有序广播（使用`sendOrderedBroadcast()`）是同步的，广播按接收者的优先级顺序逐一传递，高优先级的接收者可以处理、修改数据，甚至中止广播，阻止其向下传递。</div>
          </div>
          <div class="card-source">来源: 广播的类型</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">在有序广播中，接收者如何将处理结果传递给下一个接收者，或者如何完全中止广播的传递？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">在有序广播的`onReceive`方法中，接收者可以通过调用`setResultData()`方法将数据传递给下一个接收者。如果想完全阻止广播继续传递，可以调用`abortBroadcast()`方法。</div>
          </div>
          <div class="card-source">来源: 广播的类型 > 有序广播 (Ordered Broadcasts)</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">注册BroadcastReceiver有哪两种主要方式？它们各自的适用场景是什么？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">主要有两种注册方式：静态注册和动态注册。静态注册通过在`AndroidManifest.xml`文件中使用`<receiver>`标签声明，适用于应用即使未运行时也需要接收广播的场景（如系统启动完成）。动态注册是在代码中调用`Context.registerReceiver()`方法，其生命周期与注册它的组件（如Activity）绑定，适用于只需要在应用特定生命周期内监听广播的场景。</div>
          </div>
          <div class="card-source">来源: BroadcastReceiver 的注册</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">限制</div>
          <div class="card-question">从Android 8.0（API 26）开始，对静态注册的广播接收器施加了什么重要限制？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">限制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">针对Android 8.0或更高版本的应用，系统对静态注册施加了限制。应用无法再使用`AndroidManifest.xml`为大多数隐式广播（即没有明确指定应用组件的广播）注册接收器。但一些特殊的广播，如`ACTION_BOOT_COMPLETED`，不受此限制。</div>
          </div>
          <div class="card-source">来源: 静态注册的限制 (Android 8.0+)</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">机制</div>
          <div class="card-question">BroadcastReceiver的`onReceive()`方法有什么重要的执行限制？为什么不能在该方法中执行耗时操作？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">机制</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">`onReceive()`方法运行在主线程上，并且其生命周期非常短，通常只有大约10秒。如果在该方法中执行耗时操作，会导致UI线程阻塞，并可能触发“应用无响应”（ANR）错误。因此，它只应用于执行少量、快速的工作，如启动Service来处理耗时任务。</div>
          </div>
          <div class="card-source">来源: BroadcastReceiver 的生命周期与 onReceive() 方法</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">技术</div>
          <div class="card-question">什么是本地广播（LocalBroadcastManager）？使用它相比全局广播有什么优势？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">技术</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">LocalBroadcastManager是一个用于在单个应用内部发送和接收广播的辅助类。相比全局广播，它的优势主要有两点：1. 安全性高，因为广播数据不会离开应用，无需担心被其他应用接收导致数据泄露。2. 效率更高，因为它不涉及跨进程通信（IPC），操作更轻量。</div>
          </div>
          <div class="card-source">来源: 本地广播 (LocalBroadcastManager)</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">安全</div>
          <div class="card-question">在使用广播时，可以采取哪些措施来保证通信的安全性，防止数据泄露或被恶意应用利用？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">安全</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">可以采取以下安全措施：1. 发送广播时指定权限，只有声明了该权限的接收者才能接收。2. 注册接收器时指定权限，只有具有该权限的发送者才能向其发送广播。3. 使用本地广播（LocalBroadcastManager）确保广播只在应用内部传递。4. 发送广播时使用`setPackage()`方法指定接收应用的包名，实现点对点通信。</div>
          </div>
          <div class="card-source">来源: 安全注意事项</div>
        </div>
      </div>
    </div>

    <div class="card-container" onclick="this.classList.toggle('flipped');">
      <div class="card">
        <div class="card-face card-front">
          <div class="card-category">最佳实践</div>
          <div class="card-question">为什么对于动态注册的BroadcastReceiver，在组件销毁时进行注销（unregister）是至关重要的？</div>
          <div class="card-footer">点击卡片查看答案</div>
        </div>
        <div class="card-face card-back">
          <div class="card-category">最佳实践</div>
          <div class="card-answer-wrapper">
            <div class="card-answer">如果不及时注销动态注册的接收器，会导致内存泄漏，因为系统会一直持有对该接收器及其上下文（如Activity）的引用。此外，它还可能在组件不可见后继续接收广播，造成不必要的系统开销和潜在的应用逻辑错误。因此，最佳实践是在`onPause()`或`onDestroy()`等生命周期回调中调用`unregisterReceiver()`。</div>
          </div>
          <div class="card-source">来源: 动态注册</div>
        </div>
      </div>
    </div>

      </div>
    </body>
    </html>
